/*
 * @Author: fuqiming hb.fuqiming@aisino.com
 * @Date: 2024-03-09 18:02:04
 * @LastEditors: fuqiming hb.fuqiming@aisino.com
 * @LastEditTime: 2024-03-10 19:06:41
 * @Description: 
 */

import axios, { AxiosInstance, AxiosResponse, AxiosRequestConfig, AxiosResponseHeaders } from 'axios'
import { ExtendPrototype } from './global'

const http: AxiosInstance = axios.create({
  timeout: 30000,
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'
  }
})

const getBadRes = function (data?: AnyObject, statusText?: string, headers?: AxiosResponseHeaders, config?: AxiosRequestConfig) {
  return {
    data: data ?? "X_X",
    status: "500",
    statusText: statusText ?? "500",
    headers: headers ?? {},
    config: config ?? {},
  }
}

const PathDecorator = function (value?: string) {
  // 注意,尽量不要用prototype来改写原型
  // return (target) => {
  //   target.prototype.url = url ?? ''
  // }
  return function classDecorator<T extends { new(...args: any[]): {} }>(target: T) {
    return class extends target {
      fqm: string = value ?? 'fqmyysjjd'
    };
  }
}

const Request: MethodDecorator = function (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
  const originalMethod: Function = descriptor.value
  descriptor.value = async function (config: AxiosRequestConfig) {
    try {
      // 这里的this指向target
      console.log(this)
      let res: AxiosResponse = await http.request(config)
      return originalMethod.call(this, config, res)
    }
    catch (err) {
      console.log(err)
      // throw err
      return originalMethod.call(this, config, getBadRes())
    }
  }
}

const Get = function (url?: string) {
  return function <T>(target: T, propotypeKey: string | symbol, descriptor: PropertyDescriptor) {
    const originalMethod: Function = descriptor.value
    descriptor.value = async function (config: AxiosRequestConfig) {
      try {
        let res: AxiosResponse = await http.get(url ?? '/', config ?? {})
        return originalMethod.call(this, config, res)
      }
      catch (err) {
        console.log(err)
        // throw err
        return originalMethod.call(this, config, getBadRes())
      }
    }
  }
}

@PathDecorator()
class HttpTest extends ExtendPrototype {
  constructor() {
    super()
  }

  @Request
  request(config?: AxiosRequestConfig, res?: AxiosResponse) {
    console.log(res?.status)
    console.log(res?.data)
    return 'fqmyysjjd'
  }

  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  get(config?: AxiosRequestConfig, res?: AxiosResponse) {
    console.log(res?.status)
    console.log(res?.data.result.list)
    return 'fqmyysjjd'
  }

}

const httpTest = new HttpTest()

httpTest.request({
  'url': 'https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10',
  'method': 'get'
})

httpTest.get()

// 注意: 我这里实现的是请求后拿结果, 像nestjs是基于express的路由直接那结果, 再吧res暴露到被装饰器装饰的方法参数中
